$(function()
{
	// 動的要素に対するdraggable拡張
	jQuery.fn.liveDraggable = function (options) {
		this.live("mouseover", function() {
			// 親or子を持っている場合はdraggableにならない
			var parent_id = linked_obj["parents_" + $(this).attr("id")];
			var child_id = linked_obj["children_" + $(this).attr("id")];
			if ((!parent_id || parent_id.length == 0) && (!child_id || child_id.length == 0)) {
				if (!$(this).data("init")) {
					$(this).data("init", true).draggable(options)
				}
			}
		});
	};

	// 関連するアイデア
	// 形式：
	// linked_obj["parents_n"] = [0:親Id, 1:親の中での順番];
	// linked_obj["children_n"] = [子の配列];
	var linked_obj = new Object();
	// 選択中のオブジェクトID
	var selected_obj_id = new Array();

	var tag_canvas = $("div#canvas");
	
	// クライアントの色を決める（ランダム）
	var color_rgb = [];
	color_rgb[0] = Math.floor(Math.random() * 127); 
	color_rgb[1] = Math.floor(Math.random() * 127); 
	color_rgb[2] = Math.floor(Math.random() * 127); 
	// パステルカラーにする
	color_rgb[Math.floor(Math.random() * 3)] = 255;
	// RGBカラーの結合
	var my_color = color_rgb[0] + "," + color_rgb[1] + "," + color_rgb[2];

	// テキストボックスにフォーカスする
	$("input#text").focus();

	// サーバに接続する
	var socket = new io.Socket(null, {port: 80, rememberTransport: false});
	socket.connect();
	
	// サーバーからのメッセージ処理ハンドラを定義
	socket.on('message', function(obj)
	{
		if ('buffer' in obj)
		{
			$('div#chat').text("");
		  
			for (var i in obj.buffer)
			{
				message(obj.buffer[i]);
			}
		}
		else
		{
			message(obj);
		}
	});
	
	/**
	 * サーバーからの通知を表示する。
	 * @param obj サーバーからのメッセージオブジェクト
	 */
	function message(obj)
	{
		if ("announcement" in obj)
		{
			$("<p>").append($("<em>").text(esc(obj.announcement))).appendTo($("div#chat"));
		}
		else if ("message" in obj)
		{
			$("<p>").append($("<b>").text(esc(obj.message[0]) + ":")).append(esc(obj.message[2])).appendTo($("div#chat"));
			createIdea(obj.message[1], obj.message[2], obj.message[3], obj.message[4], 100);
			// TODO:要仕様検討
			//transparent(obj.message[1]);
		}
		$("div#chat").attr("scrollTop", "1000000");
	}
	
	/**
	 * WebSocketでメッセージを送信する。
	 */
	function send()
	{
		var text = $("input#text").val();
		var parent_id = selected_obj_id.length > 0 ? selected_obj_id[0] : undefined;
		
		$("input#text").val("");
		socket.send({ message: [text, my_color, parent_id] });
	}
	
	/**
	 * エスケープを行う。
	 * @param string msg 対象文字列
	 * @return 
	 */
	function esc(msg)
	{
		return msg.replace(/</g, '&lt;').replace(/>/g, '&gt;');
	}
	
	/**
	 * アイデア表示領域を作成する。
	 * @param string obj_id アイデアのID
	 * @param string txt 表示テキスト
	 * @param string color [R,G,B]形式のカラー情報（例：255,255,255）
	 * @param string parent_id 親アイデアのID
	 * @param number size アイデアの直径
	 */
	function createIdea(obj_id, txt, color, parent_id, size)
	{
		var left, top;
		var parent_idea = $("div#" + parent_id);
		var isDraggable = "enable";

		// 親アイデアが選択されていない場合
		if (!parent_id || parent_idea.length == 0) {
			// アイデア描画位置をランダムに設定する 
			left = tag_canvas.position().left + Math.floor(Math.random() * (tag_canvas.width() - size));
			top = tag_canvas.position().top + Math.floor(Math.random() * (tag_canvas.height() - size));
		}
		// アイデアが選択されている場合
		else {
			// 親のサイズを増やす
			var parent_size = eval(parent_idea.css("width").replace("px", "")) + 15;
			updateIdeaSize(parent_id, parent_size);
			// それまでの子の位置を調整する
			fixIdea(parent_id);
			
			// 選択したアイデアに関連する子アイデアを保存
			if (linked_obj["children_" + parent_id]) {
				linked_obj["children_" + parent_id].push(obj_id)
			}
			else {
				linked_obj["children_" + parent_id] = [obj_id];
			}

			// 親アイデアに対する順番を取得
			var child_no = linked_obj["children_" + parent_id].length - 1;
			
			// 入力したアイデアに関連する親アイデア保存
			linked_obj["parents_" + obj_id] = [parent_id, child_no];
			// 新しいアイデアの位置を指定
			var position = getChildPosition(parent_id, child_no);
			left = position[0];
			top = position[1];
			
			// 親をドラッグ不可にする
			parent_idea.draggable("disable");
		}
	
		// アイデアを描画
		var new_idea = $("<div>")
			.addClass("idea")
			.attr("id", obj_id)
			.css({
				"left" : left + "px",
				"top" : top + "px",
				"width" : size + "px",
				"height" : size + "px",
				"-moz-border-radius" : Math.floor(size)/2 + "px",
				"-webkit-border-radius" : Math.floor(size)/2 + "px",
				"background" : "-moz-radial-gradient( cover, rgba(" + color + ",1), rgba(255, 255, 255, 1))",
				"background-image" : "-webkit-gradient(radial, center center, 0, center center, " + size * 0.75 + ", from(rgba(" + color + ", 1)), to(rgba(255, 255, 255, 1)))",
				"border" : "1px solid rgba(" + color + ", 0.7)"
			})
			.appendTo(tag_canvas);

		// メッセージを描画(中央に配置) 
		$("<p>").text(txt).appendTo(new_idea).center(); 
	}
	
	/**
	 * 親オブジェクトの位置から子アイデアの位置を求める
	 * @param {string} parent_obj_id
	 * @param {number} child_no
	 */
	function getChildPosition(parent_obj_id, child_no) {
		// 親オブジェクト
		var parent_idea = $("div#" + parent_obj_id);
		// 子オブジェクト
		var child_idea = $("div#" + linked_obj["children_" + parent_obj_id][child_no]);
		// 子アイデアの順番に従って角度を決める
		var deg = child_no * 45 % 360;
		// 親アイデアの親に対する角度を加算する
		if (linked_obj["parents_" + parent_obj_id]) {
			deg += linked_obj["parents_" + parent_obj_id][1] * 45 % 360;
		}
		
		// 選択したアイデアと入力したアイデアとの中心点の最短距離を算出する
		var child_size = 100;// デフォルトサイズ
		if (child_idea.length > 0) {
			child_size = eval(child_idea.css("width").replace("px", ""));
		}
		var child_radius = child_size / 2;
		var parent_radius = eval(parent_idea.css("width").replace("px", "")) / 2;
		var distant = parent_radius + child_radius;
		// 選択したアイデアの左上の座標を取得する
		var parent_left = eval(parent_idea.css("left").replace("px", ""));
		var parent_top = eval(parent_idea.css("top").replace("px", ""));
		// 選択したアイデアの中心点を求める（※囲む子の半径分、左にずらす必要がある）
		var parent_center_x = parent_left + parent_radius - child_radius;
		var parent_center_y = parent_top + parent_radius - child_radius;
		// 子の座標を求める
		var x = parent_center_x + distant * Math.cos(deg * Math.PI / 180);
		var y = parent_center_y + distant * Math.sin(deg * Math.PI / 180);
		
		return [x, y];
	}

	/**
	 * 親アイデアを中心にアイデアの位置とサイズを調整する
	 * @param {string} obj_id
	 */
	function fixIdea(obj_id)
	{
		var linked_children_id = linked_obj["children_" + obj_id];
		for (var i = 0; linked_children_id && i < linked_children_id.length; i++) {
			var position = getChildPosition(obj_id, i);
			updateIdea(linked_children_id[i], position[0], position[1]);
			fixIdea(linked_children_id[i]);
		}
	}

	/**
	 * アイデアの位置とサイズを変更する
	 * @param {string} obj_id オブジェクトID
	 * @param {number} left
	 * @param {number} top
	 * @param {number} size
	 */
	function updateIdea(obj_id, left, top, size)
	{
		if (!size) {
			size = $("div#" + obj_id).css("width").replace("px", "");
		}
		
		$("div#" + obj_id)
			.css({
				"left" : left + "px",
				"top" : top + "px",
				"width" : size + "px",
				"height" : size + "px",
				"-moz-border-radius" : Math.floor(size)/2 + "px",
				"-webkit-border-radius" : Math.floor(size)/2 + "px",
			});
	}

	/**
	 * アイデアのサイズを変更する
	 * @param string obj_id
	 * @param number left
	 * @param number top
	 * @param number size
	 */
	function updateIdeaSize(obj_id, size)
	{
		var idea = $("div#" + obj_id);
		
		$("div#" + obj_id)
			.css({
				"width" : size + "px",
				"height" : size + "px",
				"-moz-border-radius" : Math.floor(size)/2 + "px",
				"-webkit-border-radius" : Math.floor(size)/2 + "px"
			});
	}
	
	/**
	 * 古いアイデアから透明度を上げる
	 * @param string obj_id
	 * @return 
	 */
	function transparent(obj_id)
	{
		var i = obj_id - 1;
		var idea = $("div#" + i);
		var opacity = 0;
		
		// アイデアが存在するかカウンタがプラスの間
		while (idea != undefined && i > 0) 
		{
			opacity = 1 - (obj_id - i) * 0.1;

			// アイデアが可視状態ならそのまま表示
			if (opacity > 0) 
			{
				idea.css({ opacity: opacity });
			}
			// アイデアが不可視状態ならアイデアを削除する
			else
			{
				idea.remove();
			}
			i --;
			idea = $("div#" + i);
		}
	}
	
	// 送信ボタンのクリックイベントハンドラ登録
	$("input#send_msg").click(function ()
	{
		// 空文字は送信しない
		if ($("input#text").val()) {
			send();
		}
		// テキストボックスにフォーカスする
		$("input#text").focus();
	});
	
	// テキストボックスのEnter Key押下にてボタンクリックを再現する
	$("input#text").keydown(function(e)
	{
		if (e.keyCode == 13)
		{
			$("input#send_msg").click();
		}
	});

	// アイデアを選択する
	$("div.idea").live("click", function()
	{
		// とりあえず今選べるのは一個だけ
		// 他のものを選択したら先の選択は外れる
		var prev_id = selected_obj_id.pop();
		if (prev_id)
		{
			$("div#" + prev_id).css(
			{
				"-webkit-animation-name": "fuyo_motion"
			});
		}

		if (prev_id != $(this).attr("id")) {
			$(this).css({
				"-webkit-animation-name": "fuyopika_motion"
			});
			selected_obj_id.push($(this).attr("id"));
		}
		$("input#text").focus();
	});
	
	// アイデアにhoverを設定する
	$("div.idea").live("hover", 
		function(e) {
			// マウスオーバー時に最前面にする
			switch (e.type) {
				case "mouseenter":
					$(this).css("z-index", $(this).css("z-index") + 10000);
				break;
				case "mouseleave":
					$(this).css("z-index", $(this).css("z-index") - 10000);
				break;
				default:
				break;
			}
		}
	);
	
	// アイデアにdraggableを設定する
	$("div.idea").liveDraggable({
		snap: ".idea",
		containment: "#canvas",
		opacity: 0.5,
		cursor: 'move',
		zIndex: 10000
	});
});
